/*
 *  Copyright 2013 Utkin Dmitry
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <QDebug>
#include <QList>
#include <QCoreApplication>
#include <QFileInfo>
#include <QHostAddress>
#include <QStringList>
#include <protoqtrpc/location/LocationServiceClient.h>

namespace protoqtrpc
{
namespace location
{

void help()
{
    qWarning() << QFileInfo(QCoreApplication::instance()->applicationFilePath()).
                  fileName().toUtf8().constData()
               << "[OPTIONS] command [arguments]\n"
                  "\n options:\n"
                  "   --host LOCATION_SERVICE_HOST_ADDR\n"
                  "   --port LOCATION_SERVICE_PORT\n"
                  "\n commands:\n"
                  "   getServerInfo <server_name>\n"
                  "   getServiceInfo <server_name> <service_name>\n"
                  "   locateService <service_name> [<server_host>][<server_name>]\n"
                  ;
}

QDebug operator<<(QDebug stream,
                  const LocationServiceClient::ServerInfo& serverInfo)
{
    return stream
            << "\n\n================================\n"
            << "Server\n  name: " << serverInfo.name
            << "\n  description: " << serverInfo.description
            << "\n  host: " << serverInfo.host
            << "\n  port: " << serverInfo.port
            << "\n  time: " << serverInfo.time;
}

QDebug operator<<(QDebug stream,
                  const LocationServiceClient::ServiceInfo& serviceInfo)
{
    return stream
            << "-------------\nService\n  name: " << serviceInfo.name
            << "\n  description: " << serviceInfo.description
            << "\n  time: " << serviceInfo.time;
}

QDebug operator<<(QDebug stream,
                  const LocationServiceClient::ServiceLocation& serviceLocation)
{
    return stream << serviceLocation.serverInfo << "\n" << serviceLocation.serviceInfo;
}

int startClient()
{
    QHostAddress host(QHostAddress::LocalHost);
    quint16 port = 0;

    QStringList args = QCoreApplication::instance()->arguments();

    if (args.size() < 2)
    {
        help();
        return 1;
    }

    forever
    {
        args.pop_front(); // remove app name and next parameter value
        const QString& arg = args.first();
        if (arg == "--host")
        {
            args.pop_front();
            if (args.empty())
            {
                qWarning() << "location server host is not set";
                help();
                return 1;
            }
            host = QHostAddress(args[0]);
        }
        else
        if (arg == "--port")
        {
            args.pop_front();
            if (args.empty())
            {
                qWarning() << "location server port is not set";
                help();
                return 1;
            }
            port = static_cast<quint16>(args[0].toUInt());
        }
        else
        {
            break;
        }
    }

    if (args.empty())
    {
        qWarning() << "no command to execute";
        help();
        return 1;
    }

    LocationServiceClient client(host, port);

    if (args[0] == "getServerInfo")
    {
        if (args.size() != 2)
        {
            qWarning() << "invalid number of params for " << args[0];
            help();
            return 1;
        }

        LocationServiceClient::ServerInfo info;
        LocationServiceClient::Status status =
                client.getServerInfo(args[1], info);

        if (status != LocationServiceClient::STATUS_SUCCESS)
        {
            qWarning() << "Failed to invoke LocationService: %d" << status;
            return 1;
        }

        qDebug() << info;
    }
    else if (args[0] == "getServiceInfo")
    {
        if (args.size() != 3)
        {
            qWarning() << "invalid number of params for " << args[0];
            help();
            return 1;
        }

        LocationServiceClient::ServiceInfo info;
        LocationServiceClient::Status status =
                client.getServiceInfo(args[1], args[2], info);

        if (status != LocationServiceClient::STATUS_SUCCESS)
        {
            qWarning() << "Failed to invoke LocationService: %d" << status;
            return 1;
        }

        qDebug() << info;
    }
    else if (args[0] == "locateService")
    {
        QList<LocationServiceClient::ServiceLocation> locations;
        LocationServiceClient::Status status;

        switch (args.size())
        {
        case 2:
            status = client.locateService(args[1], locations);
            break;
        case 3:
            status = client.locateService(args[1], locations, QHostAddress(args[2]));
            break;
        case 4:
            status = client.locateService(args[1], locations, QHostAddress(args[2]), args[3]);
            break;
        default:
            qWarning() << "invalid number of params for " << args[0];
            help();
            return 1;
        }

        if (status != LocationServiceClient::STATUS_SUCCESS)
        {
            qWarning() << "Failed to invoke LocationService: %d" << status;
            return 1;
        }

        foreach (const LocationServiceClient::ServiceLocation& location, locations)
            qDebug() << location;
    }
    else
    {
        qWarning() << "unsupported command: " << args[0];
        help();
        return 1;
    }

    return 0;
}


}
}


int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);

    return protoqtrpc::location::startClient();
}
